home *** CD-ROM | disk | FTP | other *** search
/ Scene Storm / Scene Storm - Volume 1.iso / coding / c / xvectors / vector0.02.c < prev    next >
C/C++ Source or Header  |  1995-11-05  |  16KB  |  467 lines

  1. /****************************************************************************/
  2. /*                                        */
  3. /*                3D-Rotaion Routines                    */
  4. /*                                        */
  5. /*  CrEatOr: LarZ SamuelssoN                     AD: 1993         */
  6. /*                                        */
  7. /*  Version 0.02: Now I'm using an ON-base in the rotaion sequence and I    */
  8. /*          calculate the corners of the object as linear         */
  9. /*  (FASTER)      combinations of the base. This saves a lot of muls.        */
  10. /*          Unfortunately, the increase in rotationspeed can hardly   */
  11. /*          be noticed as the drawing routines are MEGA-slow and         */
  12. /*          limits the speed of output.                    */
  13. /*          Maybe someone can write 'em in asm for me :)            */
  14. /*          I also added a routine that draws filled-vector gfx.        */
  15. /*          ( I sure hope you ppl out there got color support )        */
  16. /*                                        */
  17. /****************************************************************************/
  18.  
  19. #include <X11/Xlib.h>    /* Graphics Stuff                    */
  20. #include <X11/X.h>    /* Graphics defines                    */
  21. #include <stdio.h>    /* standard                        */
  22. #include <math.h>    /* math                            */
  23. #include <stdlib.h>    /* exit()                        */
  24. #include <string.h>    /* Yes, I'm actually gonna type an errormessage     */
  25.  
  26. #define    CORNERS 8    /* I will be rotating a cube which has 8 corners    */
  27. #define DIM    3    /* Nr of coordinates needed to descibe a corner     */
  28. #define PTS    4    /* Nr of points to contain a surface            */
  29.  
  30. typedef float   Base[ DIM ];            /* my base-vector   type    */
  31. typedef    float    Vob[ CORNERS ][ DIM ];        /* my vector-object type    */
  32.  
  33. /* Draw a line relative (ox,oy) from (x,y) to (xe, ye) on rootwindow        */
  34. void DrawLine(int x, int y, int xe, int ye, int ox, int oy);
  35.  
  36. /* Draw a solid polygon relative (ox,oy) cointained by (x1, y1) - (x4, y4)  */
  37. void DrawSolid(int x1, int y1, int x2, int y2,
  38.            int x3, int y3, int x4, int y4, int ox, int oy);
  39.  
  40. /* Set color                                    */
  41. void SetCol(char * str);
  42.  
  43. /* Initializes the X-Crap                            */
  44. void Init(void);
  45.  
  46. /* Makes X happy on exit                            */
  47. void Exit(void);
  48.  
  49. /* Clear the root (I bet you never could have guessed that)            */
  50. void Cls(void);
  51.  
  52. /* Calculates and returns the corners with perspective                */
  53. Vob * Perspect(Vob * em, int depth);
  54.  
  55. /* Calculates and 'returns' the corners rotated w1,w2,w3 using the three    */
  56. /* base-vectors e1,e2,e3                             */
  57. void Rotate(Vob * em, float matrix[][ DIM ], Base * e1, Base * e2, Base * e3);
  58.  
  59. /* Draws the object (lines) on the rootwindow with the corners scaled        */
  60. void DrawLOb(Vob * em, int s, int x, int y, int col);
  61.  
  62. /* Draws the object (solid) on the rootwindow with the corners scaled        */
  63. void DrawSOb(Vob * em, Base e1, Base e2, Base e3, int s, int x, int y, int p);
  64.  
  65. /* These are the variables set out to explore the unknown (X)                */
  66.  
  67. Display         *dpy;
  68. XPoint            mypoints[ PTS ];
  69. XColor             xcolour;
  70. GC             gc;
  71. XGCValues         xgcvalues;
  72. XSetWindowAttributes     xsetwattrs;
  73. int            scrn, pixel;
  74.  
  75. int main (int argc, char * argv[])
  76. {
  77.       int     cx = 600;    /* Center of rotation (rootwindow coords)   */
  78.     int     cy = 400;
  79.  
  80.     float     wx = 0.015;    /* Step-Rotation-Angles around the axises   */
  81.     float    wy = 0.010;
  82.     float    wz = 0.005;
  83.  
  84.     int     depth = 5;    /* Perspective depth                 */
  85.     int    scale = 200;    /* Scaling factor (in pixels)            */
  86.  
  87.     /* This is our three base vectors (if we were to rotate a 4-dim     */
  88.     /* cube we would need four base vectors). As you can see these are  */
  89.     /* unit vectors in the 3-dim euclidian space, though you could use  */
  90.     /* any other three vectors that aren't linearly dependent, but I    */
  91.     /* wouldn't recommend that as the coordinates for the cube relative */
  92.     /* those would be harder to find.                    */ 
  93.  
  94.     Base e1 = { 1, 0, 0 };
  95.     Base e2 = { 0, 1, 0 };
  96.     Base e3 = { 0, 0, 1 };
  97.  
  98.     /* This is the object we will be dealing with, hence, a cube.        */
  99.     /* The numerous ones are the coordinates of the cube's corners, but */
  100.     /* this time these will only be used as the initial position of the */
  101.     /* object. Actually we wouldn't have to use this at all, but it     */
  102.     /* makes life easier when we want to see which linear combination   */
  103.     /* of the base vectors each of the cube's corner represent.        */
  104.  
  105.     Vob     cube =
  106.     {
  107.         {  1,  1,  1 },
  108.         {  1, -1,  1 },
  109.         {  1, -1, -1 },
  110.         {  1,  1, -1 },
  111.         { -1,  1, -1 },
  112.         { -1,  1,  1 },
  113.         { -1, -1,  1 },
  114.         { -1, -1, -1 },
  115.      };
  116.  
  117.     Vob *    pos;        /* Holds the position of the cube's corners */
  118.                 /* during the calculations            */
  119.  
  120.     float matrix[ DIM ][ DIM ];
  121.  
  122.     /* This is the rotation-matrix for rotation around three axises        */
  123.     /* and I won't explain the maths needed to understand it.         */
  124.     /* Further reading: (any?) University Text about Linear Algebra        */
  125.  
  126.     matrix[0][0] =  cos(wx) * cos(wy);
  127.       matrix[0][1] = -sin(wz) * cos(wx) - sin(wx) * sin(wy) * cos(wz);
  128.       matrix[0][2] =  sin(wx) * sin(wz) - sin(wy) * cos(wx) * cos(wz);
  129.       matrix[1][0] =  sin(wz) * cos(wy);
  130.       matrix[1][1] =     cos(wx) * cos(wz) - sin(wx) * sin(wy) * sin(wz);
  131.       matrix[1][2] = -sin(wx) * cos(wz) - sin(wy) * sin(wz) * cos(wx);
  132.       matrix[2][0] =  sin(wy);
  133.       matrix[2][1] =  sin(wx) * cos(wz);
  134.       matrix[2][2] =  cos(wx) * cos(wz);
  135.  
  136.     /* Following here is the main() - function. I added some nice         */
  137.     /* command line options to make life easier....             */
  138.     /* The important part here is calling the different functions B)    */ 
  139.  
  140.     Init( );
  141.     Cls( );
  142.  
  143.     pos = &cube;
  144.     if ( argc == 1 || argc >= 3 )    
  145.     {
  146.         printf("Use with options:   -s (solid cube)\n");
  147.         printf("            -w (wireframe)\n");
  148.         exit(1);
  149.     }
  150.  
  151.     if ( !strcmp( argv[1], "-s" ) )
  152.         while (4711)
  153.         {
  154.             Cls( );  
  155.         
  156.             Rotate( pos, matrix, &e1, &e2, &e3 );    
  157.  
  158.             DrawSOb( Perspect( pos, depth ), e1, e2, e3, 
  159.                  scale, cx, cy, depth ); 
  160.         }
  161.  
  162.     if ( !strcmp( argv[1], "-w" ) )
  163.         while (4711)
  164.         { 
  165.             DrawLOb( Perspect( pos, depth ), scale, cx, cy, 
  166.                   BlackPixel(dpy, scrn) ); 
  167.                 
  168.             Rotate( pos, matrix, &e1, &e2, &e3 );
  169.  
  170.             DrawLOb( Perspect( pos, depth ), scale, cx, cy, 
  171.                  WhitePixel(dpy, scrn) ); 
  172.         }                 
  173.  
  174.     Exit( );
  175.       return 0;
  176. }
  177.  
  178. void DrawLOb(Vob * em, int s, int x, int y, int col)
  179. {
  180.     Vob v;
  181.     int i;
  182.  
  183.     /* The mathematical cube (the one we use in our calcs)     */
  184.     /* has got a sidelenght of 1+1=2, which is quite small     */
  185.     /* if we consider it as pixels. Therefore we have to     */
  186.     /* scale the vectors by a number, i e scale determines  */
  187.     /* the on-screen-size of the cube            */    
  188.  
  189.     for ( i=0; i<CORNERS; i++ )
  190.     {
  191.         v[i][0] = s*(*em)[i][0];
  192.         v[i][1] = s*(*em)[i][1];
  193.     }
  194.                 /* set color */
  195.  
  196.     xgcvalues.foreground = col;
  197.       XChangeGC (dpy,gc,GCForeground, &xgcvalues);
  198.     
  199.     /* Cube specific - depends on how the cube was defined     */
  200.     /* in the array declaration. If you draw a picture of      */
  201.     /* the cube with it's center in oirgo (0,0,0) and plot     */
  202.     /* the corners ( {1,1,1}, {1,-1,1}, etc ) it's quite       */
  203.     /* easy to see which lines should be drawn.        */
  204.  
  205.     DrawLine(v[0][0], v[0][1], v[1][0], v[1][1], x, y);
  206.     DrawLine(v[1][0], v[1][1], v[2][0], v[2][1], x, y);
  207.     DrawLine(v[2][0], v[2][1], v[3][0], v[3][1], x, y);
  208.     DrawLine(v[3][0], v[3][1], v[4][0], v[4][1], x, y);
  209.     DrawLine(v[4][0], v[4][1], v[5][0], v[5][1], x, y);
  210.     DrawLine(v[5][0], v[5][1], v[6][0], v[6][1], x, y);
  211.     DrawLine(v[6][0], v[6][1], v[7][0], v[7][1], x, y);
  212.     DrawLine(v[6][0], v[6][1], v[1][0], v[1][1], x, y);
  213.     DrawLine(v[7][0], v[7][1], v[4][0], v[4][1], x, y);
  214.     DrawLine(v[5][0], v[5][1], v[0][0], v[0][1], x, y);
  215.     DrawLine(v[1][0], v[1][1], v[6][0], v[6][1], x, y);
  216.     DrawLine(v[3][0], v[3][1], v[0][0], v[0][1], x, y);
  217.     DrawLine(v[2][0], v[2][1], v[7][0], v[7][1], x, y);
  218. }
  219.  
  220. void DrawSOb(Vob * em, Base e1, Base e2, Base e3, int s, int x, int y, int p)
  221. {
  222.     Vob v;
  223.     float num;
  224.     int i;
  225.                   /* scaling */
  226.  
  227.     for ( i=0; i<CORNERS; i++ )
  228.     {
  229.         v[i][0] = s*(*em)[i][0];
  230.         v[i][1] = s*(*em)[i][1];
  231.     }
  232.     
  233.     /* This is going to be difficult to explain, because     */
  234.     /* the formula was something of a longshot.        */
  235.     /* When deciding which sides to draw you'll have to     */
  236.     /* have some relation with the perspective. With     */
  237.     /* perspective the sides should be filled somewhat     */
  238.     /* later than without perspective to prevent the sides  */
  239.     /* from overwriting eachother. If you look at the wire- */
  240.     /* frame model you'll probably see what I mean.     */
  241.  
  242.     if (p) num = (float) 1/p;
  243.     else   num = 0;
  244.  
  245.     /*        Time to fill those sides with color        */
  246.     /* Let's look at a cube without perspective first. We    */
  247.     /* need to know when to draw which side. Start by      */
  248.     /* giving each side of the cube a corresponding number, */
  249.     /* like a dice. Now we need a to construct a normal     */
  250.     /* to each side (a normal to a plane is a vector such     */
  251.     /* that every angle between the vector and the plane is */
  252.     /* straight). Using the cube-object we've already got   */
  253.     /* these vector as a nice spin off from our base.    */
  254.     /* Hence:    Side nr        Normal            */
  255.     /*           1          e1            */
  256.     /*           2         -e1            */
  257.     /*           3          e2            */
  258.     /*           4         -e2            */
  259.     /*           5          e3            */
  260.     /*           6         -e3            */
  261.     /* This leaves us just to check if the normal is     */
  262.     /* pointing towards or away from us, i e is the     */
  263.     /* z-coordinate negative or positive.             */
  264.     /* The only difference when using perspective is that   */
  265.     /* the angle between the normal and the (x,y)-plane    */
  266.     /* must pass a certain value if the side should be     */
  267.     /* drawn. This can be achieved by checking the value    */
  268.     /* of the z-coordinate if the normal. If it's larger     */
  269.     /* than a value, which is related to the perspective,   */
  270.     /* then we should draw the side...             */
  271.     /* This is done as follows:                */
  272.  
  273.     /* 1 */
  274.     SetCol("blue");
  275.     if ( e1[ DIM-1 ] > num )
  276.         DrawSolid(v[0][0], v[0][1], v[1][0], v[1][1], 
  277.               v[2][0], v[2][1], v[3][0], v[3][1], x, y);
  278.     /* 2 */
  279.     SetCol("blue");
  280.     if ( e1[ DIM-1 ] < -num )
  281.         DrawSolid(v[4][0], v[4][1], v[5][0], v[5][1], 
  282.               v[6][0], v[6][1], v[7][0], v[7][1], x, y);
  283.     /* 3 */
  284.     SetCol("cornflower blue");
  285.     if ( e2[ DIM-1 ] > num )
  286.         DrawSolid(v[0][0], v[0][1], v[3][0], v[3][1], 
  287.               v[4][0], v[4][1], v[5][0], v[5][1], x, y);
  288.     /* 4 */
  289.     SetCol("cornflower blue");
  290.     if ( e2[ DIM-1 ] < -num )
  291.         DrawSolid(v[1][0], v[1][1], v[2][0], v[2][1], 
  292.               v[7][0], v[7][1], v[6][0], v[6][1], x, y);
  293.     /* 5 */
  294.     SetCol("darkslateblue");
  295.     if ( e3[ DIM-1 ] > num )
  296.         DrawSolid(v[0][0], v[0][1], v[1][0], v[1][1], 
  297.               v[6][0], v[6][1], v[5][0], v[5][1], x, y);
  298.     /* 6 */
  299.     SetCol("darkslateblue");
  300.     if ( e3[ DIM-1 ] < -num )
  301.         DrawSolid(v[3][0], v[3][1], v[2][0], v[2][1], 
  302.               v[7][0], v[7][1], v[4][0], v[4][1], x, y);
  303. }
  304.  
  305. /* This is where the perspective is calculated. I use a method where I        */
  306. /* introduce a line on parametric form from a point on the z-axis to each   */
  307. /* of the cube's corners. I let the screen be the (x,y)-plane and project   */
  308. /* the corner point on to the screen ((x,y)-plane) in the direction of the  */
  309. /* line.                                    */
  310.  
  311. Vob * Perspect(Vob * em, int depth)
  312. {
  313.     Vob temp;
  314.     int i;    
  315.  
  316.     for ( i=0;i <CORNERS; i++ )
  317.     {
  318.         temp[i][0] = (*em)[i][0]*depth/(depth-(*em)[i][2]);
  319.         temp[i][1] = (*em)[i][1]*depth/(depth-(*em)[i][2]);
  320.     }
  321.     return &temp;
  322. }
  323.  
  324. /* I guess the main changes from v0.01 to v0.02 are in this function. Here  */
  325. /* I only rotate the three base vectors and you might wonder why this is    */
  326. /* such an improvement. In v0.01 I had to rotate every vector (representing */ 
  327. /* a corner in the cube) which meant rotating eight vectors and in each     */
  328. /* rotation I use nine multiplications, hence I'll have to use CORNERS*9    */
  329. /* multiplications to rotate an object.    Now I only use DIM*9 multiplication */
  330. /* no matter how many corners I have, though the extra multiplications does */
  331. /* not vanish completely, they are substituted with CORNERS*DIM*2 adds and  */
  332. /* subs.                                    */
  333.  
  334. void Rotate(Vob * em, float matrix[][ DIM ], Base * e1, Base * e2, Base * e3)
  335. {
  336.         float te1[ DIM ];
  337.     float te2[ DIM ];
  338.     float te3[ DIM ];
  339.     int i;
  340.  
  341.     /* This is were I rotate the three base vectors.    */ 
  342.     /* I need to use temp variables as all base vectors     */
  343.     /* appear in each step of the loop.            */
  344.     /* Btw, in case you haven't noticed, this how         */
  345.     /* multiplicating a matrix with a vector works :)    */
  346.  
  347.     for ( i=0; i<DIM; i++ )            
  348.     {
  349.           te1[i] = matrix[i][0]*(*e1)[0] +
  350.                  matrix[i][1]*(*e1)[1] +
  351.              matrix[i][2]*(*e1)[2];
  352.           te2[i] = matrix[i][0]*(*e2)[0] +
  353.                  matrix[i][1]*(*e2)[1] +
  354.              matrix[i][2]*(*e2)[2];
  355.           te3[i] = matrix[i][0]*(*e3)[0] +
  356.                  matrix[i][1]*(*e3)[1] +
  357.              matrix[i][2]*(*e3)[2];
  358.     }
  359.  
  360.     for ( i=0; i<DIM; i++ ) 
  361.     {
  362.         (*e1)[i] = te1[i];
  363.         (*e2)[i] = te2[i];
  364.         (*e3)[i] = te3[i];
  365.     }
  366.  
  367.     /* Now it's time to remember those inital coordinates    */
  368.     /* of our object. Here we express the coordinates of     */
  369.     /* the corners relative our base e1,e2,e3. Here's a     */
  370.     /* short example of how it works:             */
  371.     /* Let's say one of the corners had the initial coords  */
  372.     /* {  1,  1, -1 }, now we need to find the linear     */
  373.     /* combination of e1,e2 and e3 that corresponds to this */
  374.     /* vector (I suppose knowledge of vector algebra could    */
  375.     /* be useful). It's quite easy, {1,1,-1} is the same     */
  376.     /* as e1 + e2 - e3 because                */
  377.     /*         {a,b,c} + {d,e,f} = {a+d,b+e,c+f}        */
  378.     /* So, what the following does is calculating the new   */
  379.     /* position of the object relative the rotated base.     */
  380.     /* If you change object you'll need to change these     */
  381.     /* lines also. I'll be talking more about this in     */
  382.     /* the following versions.                */
  383.  
  384.     for ( i=0; i<DIM; i++ )
  385.     {
  386.         (*em)[0][i] =   (*e1)[i] + (*e2)[i] + (*e3)[i];
  387.         (*em)[1][i] =   (*e1)[i] - (*e2)[i] + (*e3)[i];
  388.         (*em)[2][i] =   (*e1)[i] - (*e2)[i] - (*e3)[i];
  389.         (*em)[3][i] =   (*e1)[i] + (*e2)[i] - (*e3)[i];
  390.         (*em)[4][i] = - (*e1)[i] + (*e2)[i] - (*e3)[i];
  391.         (*em)[5][i] = - (*e1)[i] + (*e2)[i] + (*e3)[i];
  392.         (*em)[6][i] = - (*e1)[i] - (*e2)[i] + (*e3)[i];
  393.         (*em)[7][i] = - (*e1)[i] - (*e2)[i] - (*e3)[i];
  394.     }
  395. }
  396.  
  397. /* Someone showed me how to initialize a screen and stuff in X so I can't   */
  398. /* explain any of the following stuff... The imprortance is that they work  */
  399. /* and the drawing routines are probably a bit different on the machines    */
  400. /* I'll be using these routines on later...                    */
  401.  
  402. void DrawLine(int x, int y, int xe, int ye, int ox, int oy)
  403. {
  404.     XDrawLine(dpy, RootWindow(dpy,scrn), gc, ox+x, oy+y, ox+xe, oy+ye);
  405. }
  406.  
  407. /* Well.. I actually had to figure this one out by myself...            */
  408.  
  409. void DrawSolid(int x1, int y1, int x2, int y2, int x3, int y3, 
  410.            int x4, int y4, int ox, int oy)
  411. {
  412.     mypoints[0].x = ox + x1;
  413.     mypoints[0].y = oy + y1;
  414.     mypoints[1].x = ox + x2;
  415.     mypoints[1].y = oy + y2;
  416.     mypoints[2].x = ox + x3;
  417.     mypoints[2].y = oy + y3;
  418.     mypoints[3].x = ox + x4;
  419.     mypoints[3].y = oy + y4;
  420.  
  421.     XFillPolygon(dpy, RootWindow(dpy, scrn), gc, mypoints, PTS, 
  422.              Convex, CoordModeOrigin);
  423. }
  424.  
  425. void SetCol(char * str)
  426. {
  427.       if (XParseColor (dpy, DefaultColormap(dpy,scrn), str, &xcolour))
  428.             if (XAllocColor (dpy, DefaultColormap(dpy,scrn), &xcolour))
  429.             xgcvalues.foreground = xcolour.pixel;
  430.     XChangeGC (dpy,gc,GCForeground, &xgcvalues);
  431. }
  432.  
  433. void Cls(void)
  434. {
  435.         XClearWindow(dpy,RootWindow(dpy,scrn));
  436. }
  437.  
  438. void Init(void)
  439. {
  440.     if (!(dpy = XOpenDisplay (NULL))) 
  441.        {
  442.               fprintf (stderr, "Cannot open display.\n");
  443.               exit(1);
  444.         }
  445.       scrn                 = DefaultScreen(dpy);
  446.     xsetwattrs.backing_store     = Always;
  447.      xsetwattrs.background_pixel     = BlackPixel(dpy,scrn);
  448.     pixel                 = WhitePixel(dpy,scrn);
  449.  
  450.       XChangeWindowAttributes(dpy,RootWindow(dpy,scrn),
  451.                  CWBackingStore|CWBackPixel,
  452.                 &xsetwattrs);
  453.       if (XParseColor (dpy, DefaultColormap(dpy,scrn), "khaki2", &xcolour))
  454.             if (XAllocColor (dpy, DefaultColormap(dpy,scrn), &xcolour))
  455.                   pixel = xcolour.pixel;
  456.  
  457.       gc = XCreateGC (dpy, RootWindow(dpy,scrn),0,NULL);
  458. }
  459.     
  460. void Exit(void)
  461. {
  462.     XFlush (dpy);
  463. }
  464.  
  465.  
  466.  
  467.